﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace GameFx.Demo
{
    public partial class GameDemo : Game
    {
        Random rnd;

        const int max_balls = 10;
        const int max_enemies = 5;

        Background background;
        Background background2;
        Plane plane;
        KeyboardState lastKeyBoardState;
        FireBall[] fireBalls;
        Enemy[] enemies;
        TextBlock fps;
        TextBlock scoreText;
        GameTime currentGameTime;
        int score;
        bool lose;

        public GameDemo() { }

        public override void LoadContent()
        {
            rnd = new Random();
            background = new Background();
            background2 = new Background();
            plane = new Plane();
            plane.SetValue(Canvas.LeftProperty, 50.0);
            plane.SetValue(Canvas.TopProperty, 100.0);
            fireBalls = new FireBall[max_balls];
            for (var i = 0; i < max_balls; i++)
            {
                fireBalls[i] = new FireBall();
            }
            enemies = new Enemy[max_enemies];
            for (var i = 0; i < max_enemies; i++)
            {
                enemies[i] = new Enemy();
            }
            lastKeyBoardState = new KeyboardState();
            fps = new TextBlock();
            scoreText = new TextBlock
            {
                Text = score.ToString(),
                FontSize = 36,
                Foreground = new SolidColorBrush(Colors.White),
                FontWeight = FontWeights.Bold
            };
            scoreText.SetValue(Canvas.LeftProperty, 5.0);
        }

        public override void UnloadContent() { }

        public override void Update(GameTime gameTime)
        {
            if (currentGameTime != null && (gameTime.Time - currentGameTime.Time).Milliseconds < 10)
                return;
            currentGameTime = gameTime;
            fps.SetValue(Canvas.LeftProperty, GameSurface.ActualWidth - 50);
            fps.SetValue(Canvas.TopProperty, GameSurface.ActualHeight - 25);
            fps.Text = string.Format("FPS: {0}", Fps.ToString());

            UpdateBackground();
            UpdatePlane();

            if (KeyboardState.ContainsKey(Key.Space))
            {
                if (KeyboardState[Key.Space])
                {
                    if (!lastKeyBoardState.ContainsKey(Key.Space) || KeyboardState[Key.Space] != lastKeyBoardState[Key.Space])
                        FireBall();
                }
            }

            if (rnd.Next(1, 1000) < 10)
            {
                NewEnemy();
            }



            UpdateBalls();
            UpdateEnemies();

            DetectCollisions();

            foreach (var key in KeyboardState.Keys)
            {
                if (!lastKeyBoardState.ContainsKey(key))
                    lastKeyBoardState.Add(key, false);
                lastKeyBoardState[key] = KeyboardState[key];
            }
        }

        private void DetectCollisions()
        {
            foreach (var enemy in enemies.Where(e => e.Alive))
            {
                foreach (var ball in fireBalls.Where(b => b.Alive))
                {
                    // Si colisionan mueren las dos
                    bool collision;
                    Rect rect = new Rect(
                            new Point(
                                    (double)enemy.GetValue(Canvas.LeftProperty),
                                    (double)enemy.GetValue(Canvas.TopProperty)),
                            new Point(
                                    (double)enemy.GetValue(Canvas.LeftProperty) + enemy.ActualWidth,
                                    (double)enemy.GetValue(Canvas.TopProperty) + enemy.ActualHeight));
                    Point point = new Point(
                                        (double)ball.GetValue(Canvas.LeftProperty) - (ball.ActualWidth / 2),
                                        (double)ball.GetValue(Canvas.TopProperty) - (ball.ActualHeight / 2));
                    collision = rect.Contains(point);
                    if (collision)
                    {
                        score += 10;
                        ball.Alive = false;
                        enemy.Alive = false;
                        return;
                    }
                }
            }
        }

        private void UpdateEnemies()
        {
            foreach (var enemy in enemies)
            {
                if (enemy.Alive)
                {
                    enemy.SetValue(Canvas.LeftProperty, (double)enemy.GetValue(Canvas.LeftProperty) - 2);
                    if ((double)enemy.GetValue(Canvas.LeftProperty) < 50 + (plane.ActualWidth / 2))
                    {
                        lose = true;
                        enemy.Alive = false;
                    }
                }
            }
        }

        private void NewEnemy()
        {
            foreach (var enemy in enemies)
            {
                if (!enemy.Alive)
                {
                    enemy.SetValue(Canvas.TopProperty, (double)rnd.Next(100, 400));
                    enemy.SetValue(Canvas.LeftProperty, (double)GameSurface.ActualWidth - 100);
                    enemy.Alive = true;
                    return;
                }
            }
        }

        private void FireBall()
        {
            foreach (var ball in fireBalls)
            {
                if (!ball.Alive)
                {
                    ball.SetValue(Canvas.TopProperty, (double)plane.GetValue(Canvas.TopProperty) + (plane.ActualHeight / 2));
                    ball.SetValue(Canvas.LeftProperty, (double)plane.GetValue(Canvas.LeftProperty) + (plane.ActualWidth / 2));
                    ball.Alive = true;
                    return;
                }
            }
        }
        private void UpdateBalls()
        {
            foreach (var ball in fireBalls)
            {
                if (ball.Alive)
                {
                    ball.SetValue(Canvas.LeftProperty, (double)ball.GetValue(Canvas.LeftProperty) + 4.5);
                    if ((double)ball.GetValue(Canvas.LeftProperty) > GameSurface.ActualWidth)
                    {
                        ball.Alive = false;
                    }
                }
            }
        }
        private void UpdatePlane()
        {
            if (KeyboardState.ContainsKey(Key.Down))
            {
                if (KeyboardState[Key.Down] && (double)plane.GetValue(Canvas.TopProperty) + plane.ActualHeight < GameSurface.ActualHeight - 10)
                {
                    plane.SetValue(Canvas.TopProperty, (double)plane.GetValue(Canvas.TopProperty) + 2.0);
                }
            }

            if (KeyboardState.ContainsKey(Key.Up))
            {
                if (KeyboardState[Key.Up] && (double)plane.GetValue(Canvas.TopProperty) > 10)
                {
                    plane.SetValue(Canvas.TopProperty, (double)plane.GetValue(Canvas.TopProperty) - 2.0);
                }
            }
        }

        double Rate
        {
            get
            {
                return 65.0 / (Fps == 0 ? 65.0 : Fps);
            }
        }

        private void UpdateBackground()
        {
            background2.Height = GameSurface.ActualHeight;
            background.Height = GameSurface.ActualHeight;
            background2.Width = background2.Height * 4;
            background.Width = background.Height * 4;
            background2.SetValue(Canvas.LeftProperty, (double)background2.GetValue(Canvas.LeftProperty) - 1);
            if (background2.ActualWidth + (double)background2.GetValue(Canvas.LeftProperty) < GameSurface.ActualWidth)
            {
                background2.SetValue(Canvas.LeftProperty, background2.ActualWidth + (double)background2.GetValue(Canvas.LeftProperty));
            }
            background.SetValue(Canvas.LeftProperty, 1 + (double)background2.GetValue(Canvas.LeftProperty) - background2.ActualWidth);
        }

        bool firstTime = true;
        public override void Draw(GameTime gameTime)
        {
            if (firstTime)
            {
                GameSurface.Children.Clear();
                GameSurface.Children.Add(background);
                GameSurface.Children.Add(background2);
                GameSurface.Children.Add(plane);
                GameSurface.Children.Add(fps);
                GameSurface.Children.Add(scoreText);
                firstTime = false;
            }
            if (lose)
            {
                GameSurface.Children.Clear();
                GameSurface.Children.Add(background);
                GameSurface.Children.Add(background2);
                var message = new TextBlock
                {
                    Text = string.Format("{0} Score \nGame Over \nPress F5 to try again", score),
                    FontSize = 48,
                    FontWeight = FontWeights.Bold,
                    TextWrapping = TextWrapping.Wrap,
                    TextAlignment = TextAlignment.Left,
                    Foreground = new SolidColorBrush(Colors.White)
                };
                message.SetValue(Canvas.LeftProperty, 50.0);
                message.SetValue(Canvas.TopProperty, 50.0);
                GameSurface.Children.Add(message);
                return;
            }
            for (var i = 0; i < max_balls; i++)
            {
                if (fireBalls[i].Alive)
                {
                    if (!GameSurface.Children.Contains(fireBalls[i]))
                    {
                        GameSurface.Children.Add(fireBalls[i]);
                    }
                }
                else
                {
                    if (GameSurface.Children.Contains(fireBalls[i]))
                    {
                        GameSurface.Children.Remove(fireBalls[i]);
                    }
                }
            }

            for (var i = 0; i < max_enemies; i++)
            {
                if (enemies[i].Alive)
                {
                    if (!GameSurface.Children.Contains(enemies[i]))
                    {
                        GameSurface.Children.Add(enemies[i]);
                    }
                }
                else
                {
                    if (GameSurface.Children.Contains(enemies[i]))
                    {
                        GameSurface.Children.Remove(enemies[i]);
                    }
                }
            }
            scoreText.Text = score.ToString();
        }
    }
}